package main

import (
	"errors"
	"fmt"
	"os"
)

/*
1、介绍
队列是一个有序列表，可以用数组或是链表来实现
遵循先入先出的原则。即：存入队列的首句，要先取。后存入的要后取出
2、数组模拟队列
(1)队列本身是有序列表，若使用数组的结构来存储队列的数据，则队列数组的声明如下，其中maxSize是该队列的最大容量
(2)因为队列的输出、输入是分别从前后端来处理，因此需要两个变量front以及rear分别记录队列前后端的下标，front会随着数据输出而改变，而rear则是随着数据输入而改变
(3)当我们将数据存入队列时称为“addqueue”，addqueue的处理需要有连个步骤：
a、将尾指针往后移：rear+1，front==rear [空]
b、若尾指针rear小于等于队列的最大下标maxSize-1，则将数据存入rear所指的数组元素中，否则无法存入数据，rear==maxSize-1 [队列满]
*/
//使用一个结构体管理队列
type Queue struct {
	maxSize int
	array   [4]int //数组 模拟队列
	front   int    //表示指向队列首部
	rear    int    //表示指向队列尾部
}

//添加数据到队列
func (this *Queue) AddQueue(val int) (err error) {
	//先判断队列是否已满
	if this.rear == this.maxSize-1 { //重要的提示，rear是队列尾部(含最后元素)
		return errors.New("queue full")
	}
	this.rear++ //rear后移
	this.array[this.rear] = val
	return
}

//从队列中取出数据
func (this *Queue) GetQueue() (val int, err error) {
	//先判断队列是否为空
	if this.rear == this.front { //队空
		return -1, errors.New("queue empty")
	}
	this.front++
	val = this.array[this.front]
	return val, err
}

//显示队列，找到队首，然后到遍历到队尾
func (this *Queue) ShowQueue() {
	fmt.Println("队列当前的情况是：")
	//this.front不包含队首的元素
	for i := this.front + 1; i <= this.rear; i++ {
		fmt.Printf("array[%d]=%d\t", i, this.array[i])
	}
	fmt.Println()
}
func main() {
	//先创建一个队列
	queue := &Queue{
		maxSize: 4,
		front:   -1,
		rear:    -1,
	}
	var key string
	var val int
	for {
		fmt.Println("1输入add表示添加数据到队列")
		fmt.Println("2输入get表示从队列获取数据")
		fmt.Println("3输入show表示显示队列")
		fmt.Println("4输入exit表示退出队列")
		fmt.Scanln(&key)
		switch key {
		case "add":
			fmt.Println("输入你要入队列的数")
			fmt.Scanln(&val)
			err := queue.AddQueue(val)
			if err != nil {
				fmt.Println(err.Error())
			} else {
				fmt.Println("加入队列ok")
			}
		case "get":
			val, err := queue.GetQueue()
			if err != nil {
				fmt.Println(err.Error())
			} else {
				fmt.Println("从队列中取出了一个数", val)
			}
		case "show":
			queue.ShowQueue()
		case "exit":
			os.Exit(0)
		}
	}
}

/*
上面的代码实现了基本队列结构，但是没有有效的利用数组空间
需要使用环形队列
*/
